﻿import flash.net.FileReference;
import mx.utils.Delegate;


dynamic class UpLoadFile {
	public static var CanSay:Boolean = true;
	/**
	 * function(loaded,total,file)
	 */
	public static var M_PROGRESS:String = "onProgress";                   
	/**
	 * function(errormessage)
	 */
	public static var M_ERROR:String = "onError";
	/**
	 * function(fileId,isCancel)
	 */
	public static var M_COMPLITE:String = "onComplite";
	
	public static var E_URLError:String = "url_error_or_empty";
	public static var E_IOError:String = "net_error_or_404_error";
	public static var E_HTTPError:String = "http_server_error_response";
	public static var E_OVERSize:String = "file_size_over_max";
	public static var E_SecurityError:String = "Security_error";
	
	public var say:Say;
	
	private var files:Array;
	private var _serverurl:String = "";
	
	/**
	 * when user selected file,this function will be action
	 * function (file):Boolean;
	 */
	public var selectRule:Function;
	
	/**
	 * page url that to upload to
	 */
	public function get ServerUrl():String
	{
		return this._serverurl;
	}
	/**
	 * page url that to upload to
	 */
	public function set ServerUrl(value:String)
	{
		this._serverurl = value;
	}
	/**
	 * Up load file class.
	 * @param	serverurl page url that to upload to
	 */
	public function UpLoadFile(serverurl:String)
	{
		AsBroadcaster.initialize(this);
		initsay();
		initvars();
		this._serverurl = serverurl;
		say.msay("inited!");
	}
	private function initvars()
	{
		files = new Array();
	}
	/**
	 * do upload action 
	 * @param	parames the parames when up load to server
	 * @param	maxSize the max file size 
	 * @param	filetype file type(FileType enum)
	 * @param	serverurl serverurl page url that to upload to
	 */
	public function upload(parames:Object, maxSize:Number, filetype:Number,serverurl:String)
	{
		if (serverurl == undefined || serverurl == "")
		{
			serverurl = this._serverurl;
		}
		if (serverurl == "" || serverurl == undefined)
		{
			this.broadcastMessage(M_ERROR, E_URLError);
			say.esay("server url Error.["+serverurl+"]");
			return ;
		}
		if (filetype == undefined || filetype < 1)
		{
			filetype = 1;
		}
		var file:FileReference = new FileReference();
		file["maxSize"] = (((maxSize == undefined) || (maxSize <= 0))? 100 * 1024 * 1024:maxSize);
		file["parames"] = parames;
		file["serverUrl"] = serverurl;
		
		initFileEvents(file);
		var id:Number = -1;
		for (var i = 0; i < files.length;i++){
			if (files[i] == null)
			{
				id = i;
				files[id] = file;
				break;
			}
		}
		if (id < 0)
		{
			id = files.push(file)-1;
		}
		file["id"] = id;
		var ar:Array = FileType.getTypeArray(filetype);
		file.browse(ar);
	}
	private function disposeFile(file:FileReference)
	{
		file.removeListener(file["listenObj"]);
		this.files[file["id"]] = null;
	}
	private function initFileEvents(file:FileReference)
	{
		var lisobj:Object = new Object();

		lisobj.onSelect = Delegate.create(this, this.onSelectedFile);
		lisobj.onCancel = Delegate.create(this, this.onCancelUpLoad);
		lisobj.onOpen =Delegate.create(this, this.onOpendFile);
		lisobj.onProgress = Delegate.create(this, this.onUpLoadProgress);
		lisobj.onUploadCompleteData = Delegate.create(this, this.onCompleteUpload);
		lisobj.onHTTPError = Delegate.create(this, this.onHTTPError);
		lisobj.onIOError = Delegate.create(this, this.onIOError);
		lisobj.onSecurityError = Delegate.create(this, this.onSecurityError);
		
		
		
		file["listenObj"] = lisobj;
		file.addListener(file["listenObj"]);
	}
	/**
	 * cancel upload.
	 * @param	id file id
	 */
	public function cancel(id:Number)
	{
		if (id < 0 || id >= this.files.length)
		{
			return ;
		}else
		{
			if (this.files[id] == null)
			{
				return;
			}
			this.files[id].cancel();
			this.onCancelUpLoad(this.files[id]);
		}
	}
	/**
	 * cancel all upload.
	 */
	public function cancelAll()
	{
		for (var i = 0; i < this.files.length; i++)
		{
			this.cancel(i);
		}
	}
	
	private function onSelectedFile(file:FileReference):Void {
		if (this.selectRule != undefined)
		{
			if (this.selectRule(file) == false)
			{
				file.cancel();
				this.onCancelUpLoad(file);
				return;
			}
		}
		if (file["maxSize"] < file.size)
		{
			this.broadcastMessage(M_ERROR, E_OVERSize);
			say.esay("file too large.[" + file.size + "b/" + file["maxSize"] + "b]");
			disposeFile(file);
			return;
		}
		var serverString:String = "";
		serverString += file["serverUrl"];
		if (serverString.indexOf("?") >= 0)
		{
			serverString += "&originalFileName=" + file.name;
		}else
		{
			serverString += "?originalFileName=" + file.name;
		}
		
		for (var i:String in file["parames"])
		{
			serverString += "&" + i + "=" + file["parames"][i];
		}
		say.msay("ready to upload file [" + file.name + "] URL:[" + serverString + "]");
		if(!file.upload(serverString)) {
			this.broadcastMessage(M_ERROR, E_URLError);
			say.esay("stop upload error.");
			disposeFile(file);
		}
	}

	function onCancelUpLoad(file:FileReference):Void {
		this.broadcastMessage(M_COMPLITE, file["id"],false);
			say.esay("user canceled upload.");
			disposeFile(file);
	}

	function onOpendFile(file:FileReference):Void {
		say.msay("opened file " + file.name);
	}

	function onUpLoadProgress(file:FileReference, bytesLoaded:Number, bytesTotal:Number):Void {
		this.broadcastMessage(M_PROGRESS, bytesLoaded, bytesTotal, file);
		say.msay("upload " + file.name + " [" + bytesLoaded + "/" + bytesTotal + "]");
	}

	function onCompleteUpload(file:FileReference,data:Object):Void {
		this.broadcastMessage(M_COMPLITE, file["id"],true,data);
		say.msay("upload complited!");
		disposeFile(file);
	}

	function onHTTPError(file:FileReference, n:Number):Void {
		say.msay("httpcode:" + n);
		if (n >= 400 && n<600)
		{
			if (n == 404)
			{
				say.esay(E_IOError);
				this.broadcastMessage(M_ERROR, E_IOError);
				this.disposeFile(file);
			}else
			{
				say.esay(E_HTTPError + "[code:" + n + "]");
				this.broadcastMessage(M_ERROR, E_HTTPError + "[code:" + n + "]");
				this.disposeFile(file);
			}
		}
	}

	function onIOError(file:FileReference):Void {
		say.esay(E_IOError);
		this.broadcastMessage(M_ERROR, E_IOError);
		this.disposeFile(file);
	}

	function onSecurityError(file:FileReference, errorString:String):Void {
		say.esay(E_SecurityError);
		this.broadcastMessage(M_ERROR, E_SecurityError);
		this.disposeFile(file);
	}
	
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	private function initsay()
	{
		say = new Say("uploadf");
		this[Say.M_SAY] = this.____sayfun;
		say.addListener(this);
	}
	private function ____sayfun(o:Object)
	{
		if(CanSay){
			trace(o);
		}
	}
}